package com.coderman.daoclient.utils;

import com.coderman.daoclient.annotations.ColId;
import com.coderman.daoclient.annotations.Column;
import com.coderman.daoclient.annotations.Table;
import com.coderman.daoclient.enums.FieldTypeEnum;
import com.coderman.daoclient.reflect.FieldInfo;

import java.io.File;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * Created by ${fanchunshuai} on 2017-7-26.
 *
 * @version: V1.0
 * @Desc:
 */
public class ClassUtils {
    private static volatile  List<Class<?>> beanList = new ArrayList<>();

    /**
     * 获取所有带有table注解的javabean模型
     * @return
     * @throws Exception
     */
    public synchronized static Map<Class<?>,List<FieldInfo>> getBean()throws Exception{
        if(beanList.isEmpty()){
            searchClass();
        }

        Map<Class<?>,List<FieldInfo>> classListMap = new HashMap<>();
        for (Class<?> clazz : beanList){
            if(clazz.getAnnotations().length == 0){
                continue;
            }
            classListMap.put(clazz,getFieldInfoList(clazz));

        }
        return classListMap;
    }


    /**
     * 根据指定clazz获取clazz具有的属性列表
     * @param clazz
     * @return
     */
    private  synchronized  static List<FieldInfo> getFieldInfoList(Class<?> clazz){
        List<FieldInfo> fieldInfoList = new ArrayList<>();
        for (Field field : clazz.getDeclaredFields()){
            FieldInfo fieldInfo = new FieldInfo();
            Column column = field.getAnnotation(Column.class);
            if(!Objects.isNull(column)){
                fieldInfo.setFieldName(field.getName());
                fieldInfo.setColName(column.name());
                //设置是否是id
                fieldInfo.setIsID("id".equals(column.name()) ? 1 : 0);

                //生成getMethodName
                String getMethodName = field.getName().substring(0, 1).toUpperCase() + field.getName().substring(1);
                fieldInfo.setGetMethodName("get" + getMethodName);
                fieldInfo.setSetMethodName("set" + getMethodName);
                int index = FieldTypeEnum.getByTypeName(field.getGenericType().getTypeName()).getIndex();
                fieldInfo.setColType(index);
                fieldInfoList.add(fieldInfo);
            } else if(field.isAnnotationPresent(ColId.class)){
                fieldInfo.setFieldName(field.getName());
                fieldInfo.setColName("id");
                //生成getMethodName
                String getMethodName = field.getName().substring(0, 1).toUpperCase() + field.getName().substring(1);

                fieldInfo.setGetMethodName("get"+getMethodName);
                fieldInfo.setSetMethodName("set" + getMethodName);

                int index = FieldTypeEnum.getByTypeName(field.getGenericType().getTypeName()).getIndex();
                fieldInfo.setColType(index);
                fieldInfo.setIsID(1);
                fieldInfoList.add(fieldInfo);
            }
        }
        return fieldInfoList;
    }

    /**
     * 获取java模型的属性
     * @param fieldMap
     * @param classTableMap
     * @throws Exception
     */
    public synchronized static void getClassFieldMap(Map<Class<?>,List<FieldInfo>> fieldMap , Map<Class<?>,String> classTableMap )throws Exception{
        if(beanList.isEmpty()){
            searchClass();
        }
        for (Class<?> clazz : beanList){
            if(clazz.getAnnotations().length == 0) {
                continue;
            }
            Table table = (Table) clazz.getAnnotations()[0];
            if(table != null){
                classTableMap.put(clazz,table.name());
                fieldMap.put(clazz,getFieldInfoList(clazz));
            }

        }
    }

    private  static  List<String> classPaths = new ArrayList<String>();

    public static void main(String[] args) {
        try {

            //Class<?> clazz = Thread.currentThread().getContextClassLoader().loadClass("com.coderman.daoclient.bean.DBBean");
            //System.out.println(clazz.toGenericString());
            Map<Class<?>,List<FieldInfo>> classListMap = ClassUtils.getBean();
            System.out.println(classListMap.toString());

           /* Map<Class<?>,List<FieldInfo>> map = ClassUtils.getBean();

            List<FieldInfo> list = map.get(DBBean.class);
            for (FieldInfo fieldInfo : list){
                System.out.println(fieldInfo.getSetMethodName());
            }*/
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 扫描当前class上下文中的javabean类
     * @throws ClassNotFoundException
     */
    private static void searchClass() throws ClassNotFoundException {
        //包名
        //先把包名转换为路径,首先得到项目的classpath
        String classpath = ClassUtils.class.getResource("/").getPath();
        //然后把我们的包名basPach转换为路径名
        //然后把classpath和basePack合并
        doPath(new File(classpath));
        //这个时候我们已经得到了指定包下所有的类的绝对路径了。我们现在利用这些绝对路径和java的反射机制得到他们的类对象
        for (String s : classPaths) {
            s = s.replace(classpath.replace("/","\\").replaceFirst("\\\\",""),"").replace("\\",".").replace(".class","");
            Class cls = Thread.currentThread()
                    .getContextClassLoader()
                    .loadClass(s);
            if(cls.isAnnotationPresent(Table.class)){
                beanList.add(cls);
            }
        }
    }


    /**
     * 该方法会得到所有的类，将类的绝对路径写入到classPaths中
     * @param file
     */
    private static void doPath(File file) {
        if (file.isDirectory()) {//文件夹
            //文件夹我们就递归
            File[] files = file.listFiles();
            for (File f1 : files) {
                doPath(f1);
            }
        } else {//标准文件
            //标准文件我们就判断是否是class文件
            if (file.getName().endsWith(".class")) {
                //如果是class文件我们就放入我们的集合中。
                classPaths.add(file.getPath());
            }
        }
    }

}
